home *** CD-ROM | disk | FTP | other *** search
- /**
- *** IPDial - Serial.c
- ***
- *** This file implements the communication with the serial.device.
- ***
- ***
- *** This program is free software; you can redistribute it and/or modify
- *** it under the terms of the GNU General Public License as published by
- *** the Free Software Foundation; either version 2 of the License, or
- *** (at your option) any later version.
- ***
- *** This program is distributed in the hope that it will be useful,
- *** but WITHOUT ANY WARRANTY; without even the implied warranty of
- *** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- *** GNU General Public License for more details.
- ***
- *** You should have received a copy of the GNU General Public License
- *** along with this program; if not, write to the Free Software
- *** Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- ***
- *** Authors: Jochen Wiedmann <wiedmann@neckar-alb.de>
- *** Stefan Gybas <cab@studbox.uni-stuttgart.de>
- **/
-
-
-
-
- /**
- *** Include files
- **/
- #ifndef IPDIAL_H
- #include "IPDial.h"
- #endif
- #include <ctype.h>
- #include <devices/serial.h>
- #include <devices/timer.h>
-
- #ifndef MIN
- #define MIN(a,b) (((a)>(b))?(b):(a))
- #endif
-
-
-
-
-
- /**
- *** Local variables.
- **/
- STATIC APTR MySerReq = NULL;
- STATIC APTR MyTimeReq = NULL;
- STATIC UBYTE SerBuffer[4096];
-
-
-
-
- /**
- *** Cleanup function.
- **/
- VOID SerialCleanup(VOID)
-
- { DeviceIODelete(MySerReq);
- DeviceIODelete(MyTimeReq);
- }
-
-
-
-
-
- /**
- *** Table of error messages created by the serial.device.
- **/
- STATIC VOID SerialShowError(ULONG Error)
-
- { STRPTR ptr;
-
- switch(Error)
- { case 1:
- ptr = (STRPTR) "Serial device busy";
- break;
- case 2:
- ptr = (STRPTR) "Baud rate not supported";
- break;
- case 4:
- ptr = (STRPTR) "Memory error";
- break;
- case 5:
- ptr = (STRPTR) "Invalid parameters";
- break;
- case 6:
- ptr = (STRPTR) "Line error";
- break;
- case 9:
- ptr = (STRPTR) "Parity error";
- break;
- case 11:
- ptr = (STRPTR) "Timer error";
- break;
- case 12:
- ptr = (STRPTR) "Buffer overflow";
- break;
- case 13:
- ptr = (STRPTR) "No DSR";
- break;
- case 15:
- ptr = (STRPTR) "Break detected";
- break;
- default:
- ptr = (STRPTR) "Unknown error";
- break;
- }
-
- fprintf(stderr, "\nserial error: %s\n", ptr);
- CleanupAndExit(10);
- }
-
-
-
-
-
- /**
- *** This function opens the serial device. It can be closed
- *** using DeviceIODelete().
- **/
- STATIC ULONG SerialDecodeProtocol(struct IOExtSer *SerReq, STRPTR Protocol)
-
- { if (stricmp((char *) Protocol, "XONXOFF") == 0)
- { SerReq->io_SerFlags &= ~(SERF_XDISABLED|SERF_7WIRE);
- }
- else if (stricmp((char *) Protocol, "NONE") == 0)
- { SerReq->io_SerFlags |= SERF_XDISABLED;
- SerReq->io_SerFlags &= ~SERF_7WIRE;
- }
- else if (stricmp((char *) Protocol, "RTSCTS") == 0 ||
- stricmp((char *) Protocol, "7WIRE") == 0)
- { SerReq->io_SerFlags |= (SERF_XDISABLED|SERF_7WIRE);
- }
- else
- { return(FALSE);
- }
- return(TRUE);
- }
-
- ULONG SerialOpen(STRPTR DeviceName, LONG Unit, LONG Baud, STRPTR Protocol)
-
- { ULONG error;
- struct IOExtSer *RealSerReq;
-
- if (VerboseMode)
- { printf(">>> Trying to open %s unit %ld at %ld baud (protocol \"%s\")\n",
- DeviceName, Unit, Baud, Protocol);
- }
-
- if (!(MySerReq = DeviceIOCreate(sizeof(struct IOExtSer))))
- { PrintError(0, "not enough memory");
- }
-
- RealSerReq = (struct IOExtSer *) DeviceIOReq(MySerReq);
- RealSerReq->io_SerFlags = 0;
-
- if (!SerialDecodeProtocol(RealSerReq, Protocol))
- { return(FALSE);
- }
-
- if ((error = DeviceIOOpen(DeviceName, Unit, MySerReq, 0)))
- { SerialShowError(error);
- }
-
- /* SerialSetProtocol(Protocol); */
- SerialSetBaud(Baud);
- SerialSetBufSize(DEFAULT_BUFSIZE);
-
- if (!(MyTimeReq = DeviceIOCreate(sizeof(struct timerequest))))
- { PrintError(0, "failed to create timer request: not enough memory");
- }
-
- if ((error = DeviceIOOpen((STRPTR) "timer.device", UNIT_VBLANK,
- MyTimeReq, 0)))
- { PrintError(0, "failed to open timer.device");
- }
- return(TRUE);
- }
-
-
-
-
-
- /**
- *** This function sends a string to the serial device.
- **/
- VOID SerialSend(STRPTR str)
-
- { struct IOExtSer *req;
- if (VerboseMode)
- { printf(">>> Sending\n");
- }
-
- req = (struct IOExtSer *) DeviceIOReq(MySerReq);
- req->IOSer.io_Length = strlen((char*) str);
- req->IOSer.io_Data = str;
- DeviceIODo(MySerReq, CMD_WRITE);
- }
-
-
-
-
-
- /**
- *** This function is used to wait for a certain string.
- ***
- *** The function will return if either a timeout occurs
- *** (never happens, if timeout == -1) or if one of the
- *** strings in the args array is read from the serial.device.
- ***
- *** Result is the number of the string or -1.
- **/
- STATIC APTR waitBuffer = NULL;
- LONG SerialWait(STRPTR *args, LONG timeout)
-
- { ULONG sigs;
- ULONG rsigs;
- BYTE error;
- struct IOExtSer *SerReq = (struct IOExtSer *) DeviceIOReq(MySerReq);
-
- if (VerboseMode)
- { printf(">>> Waiting\n");
- }
-
- /**
- *** Be sure, that the buffer is valid.
- **/
- if (!waitBuffer && !(waitBuffer = BufferCreate()))
- { PrintError(0, "not enough memory");
- }
-
- /**
- *** Clear the buffer.
- **/
- BufferClear(waitBuffer);
-
- sigs = SIGBREAKF_CTRL_C | SIGBREAKF_CTRL_F | DeviceIOSignal(MySerReq);
-
- if (timeout != -1)
- { struct timerequest *tr = (struct timerequest *) DeviceIOReq(MyTimeReq);
-
- tr->tr_time.tv_secs = timeout;
- tr->tr_time.tv_micro = 0;
- DeviceIOSend(MyTimeReq, TR_ADDREQUEST);
- sigs |= DeviceIOSignal(MyTimeReq);
- }
-
- for(;;)
- { LONG result;
-
- /**
- *** First ask, if any data is present on the serial line.
- *** Maybe the string we are waiting for is already present?
- **/
- do
- { DeviceIODo(MySerReq, SDCMD_QUERY);
- if ((result = SerReq->IOSer.io_Actual))
- { SerReq->IOSer.io_Data = SerBuffer;
- SerReq->IOSer.io_Length = MIN(sizeof(SerBuffer)-1,
- SerReq->IOSer.io_Actual);
- if ((error = DeviceIODo(MySerReq, CMD_READ)))
- { SerialShowError(error);
- }
- if (EchoMode)
- { int i;
-
- for (i = 0; i < SerReq->IOSer.io_Actual; i++)
- { putchar(SerBuffer[i]);
- }
- fflush(stdout);
- }
- BufferExtend(waitBuffer, SerBuffer, SerReq->IOSer.io_Actual);
- }
- }
- while (result);
-
-
- if ((result = BufferCheck(waitBuffer, args)) >= 0)
- { DeviceIOAbort(MyTimeReq);
- if (VerboseMode)
- { printf(">>> Found \"%s\"\n", args[result]);
- }
- return(result);
- }
-
- /**
- *** It isn't, send a request for one byte.
- **/
- SerReq->IOSer.io_Length = 1;
- SerReq->IOSer.io_Data = SerBuffer;
- DeviceIOSend(MySerReq, CMD_READ);
-
- rsigs = Wait(sigs);
-
- if (rsigs & SIGBREAKF_CTRL_F)
- { printf("\nCtrl-F\n");
- DeviceIOAbort(MySerReq);
- SerialTerminal(NULL, FALSE, FALSE);
- return(0); /* has anyone a better idea? */
- }
-
- if (rsigs & SIGBREAKF_CTRL_C)
- { printf("\nCtrl-C\n");
- DeviceIOAbort(MySerReq);
- SerialSend( (STRPTR) "\r\n"); /* hangup modem if dialing */
- CleanupAndExit(10);
- }
- else if (rsigs & DeviceIOSignal(MySerReq))
- { BYTE error;
-
- /**
- *** Data received, add it to the buffer and check for more.
- **/
- if ((error = DeviceIOWait(MySerReq)))
- { SerialShowError(error);
- }
- if (EchoMode)
- { putchar(*SerBuffer);
- fflush(stdout);
- }
- BufferExtend(waitBuffer, SerBuffer, 1);
- }
- else
- { /**
- *** Timeout
- **/
- DeviceIOWait(MyTimeReq);
- DeviceIOAbort(MySerReq);
- return(-1);
- }
- }
- }
-
-
-
-
- /**
- *** Return buffer read by the last "Wait" command.
- **/
- STRPTR SerialWaitBuffer(VOID)
-
- { if (!(waitBuffer))
- { return((STRPTR) "");
- }
- else
- { return(BufferBuffer(waitBuffer));
- }
- }
-
-
-
-
-
-
- /**
- *** This function implements a terminal mode. It gives the users input
- *** to the modem and likewise the modems output to the user, as long as
- *** the user doesn't enter Ctrl-\.
- **/
- VOID SerialTerminal(STRPTR eof, ULONG echo, ULONG lineMode)
-
- { struct DosPacket *dp;
- struct MsgPort *port = NULL;
- struct IOExtSer *SerReq = (struct IOExtSer *) DeviceIOReq(MySerReq);
- APTR SerSendReq = NULL;
- struct IOExtSer *serSendReq;
- static char buffer[128];
- static char sendBuffer[256]; /* Twice the size of buffer */
- ULONG bufSize = sizeof(buffer);
- LONG status = 10;
- BPTR cis = Input();
- ULONG sigs;
-
- if (VerboseMode)
- { printf(">>> Entering terminal mode\n");
- }
-
- if (!cis)
- { PrintError(0, "invalid input device");
- }
-
- if (!echo) {
- lineMode = FALSE;
- }
- if (!lineMode) {
- if (!SetMode(cis, TRUE))
- { PrintError(0, "can't put console into character (raw) mode");
- }
- }
-
- if ((dp = AllocDosObject(DOS_STDPKT, NULL)))
- { if ((port = CreateMsgPort()))
- { if ((SerSendReq = DeviceIOCreate(sizeof(struct IOExtSer))))
- { serSendReq = (struct IOExtSer *) DeviceIOReq(SerSendReq);
- serSendReq->IOSer.io_Device = SerReq->IOSer.io_Device;
- serSendReq->IOSer.io_Unit = SerReq->IOSer.io_Unit;
- status = 0;
- }
- }
- }
-
- if (status)
- { fprintf(stderr, "Memory error.\n");
- goto ExitSerialTerminal;
- }
-
- dp->dp_Type = ACTION_READ;
- dp->dp_Arg1 = ((struct FileHandle *) BADDR(cis))->fh_Arg1;
- dp->dp_Arg2 = (ULONG) buffer;
- dp->dp_Arg3 = bufSize;
- SendPkt(dp, (struct MsgPort *) ((struct FileHandle *) BADDR(cis))->fh_Type, port);
-
- SerReq->IOSer.io_Length = 1;
- SerReq->IOSer.io_Data = SerBuffer;
- DeviceIOSend(MySerReq, CMD_READ);
-
- sigs = (1 << port->mp_SigBit) | SIGBREAKF_CTRL_C
- | SIGBREAKF_CTRL_F | DeviceIOSignal(MySerReq);
-
- for(;;)
- { LONG rsigs;
-
- rsigs = Wait(sigs);
-
- if (rsigs & SIGBREAKF_CTRL_C) /* CTRL-C: quite with RC 5 */
- { printf("\nCtrl-C\n");
- #ifdef USE_ABORTPKT
- AbortPkt(port, dp);
- WaitPort(port);
- #endif
- status = 5;
- goto ExitSerialTerminal;
- }
-
- if (rsigs & SIGBREAKF_CTRL_F) /* CTRL-F: quite with RC 0 */
- { printf("\nCtrl-F\n");
- #ifdef USE_ABORTPKT
- AbortPkt(port, dp);
- WaitPort(port);
- #endif
- status = 0;
- goto ExitSerialTerminal;
- }
-
- if (rsigs & (1 << port->mp_SigBit))
- { int eofSeen = FALSE;
-
- GetMsg(port);
- if (dp->dp_Res1 == -1)
- { fprintf(stderr, "Error %ld while reading input.\n", dp->dp_Res2);
- status = 10;
- goto ExitSerialTerminal;
- }
- if (dp->dp_Res1 == 0)
- { eofSeen = TRUE;
- }
- else
- { int i, bufLen; /* Extend LF to CR/LF and send resulting string. */
-
- bufLen = 0;
- for (i = 0; i < dp->dp_Res1; i++)
- { if ((eof && *eof == buffer[i]) ||
- (!eof && !lineMode && buffer[i] == 0x1c))
- { eofSeen = TRUE;
- }
- if (lineMode && buffer[i] == '\n')
- { sendBuffer[bufLen++] = '\r';
- sendBuffer[bufLen++] = '\n';
- }
- else
- { sendBuffer[bufLen++] = buffer[i];
- }
- }
-
- if (bufLen > 0)
- { serSendReq->IOSer.io_Length = bufLen;
- serSendReq->IOSer.io_Data = sendBuffer;
- DeviceIODo(SerSendReq, CMD_WRITE);
- }
-
- if (!lineMode && echo)
- { fwrite(sendBuffer, bufLen, 1, stdout);
- fflush(stdout);
- }
- }
-
- if (eofSeen)
- { DeviceIOAbort(MySerReq);
- status = -1; /* don't quit IPDial */
- goto ExitSerialTerminal;
- }
-
- dp->dp_Type = ACTION_READ;
- dp->dp_Arg1 = ((struct FileHandle *) BADDR(cis))->fh_Arg1;
- dp->dp_Arg2 = (ULONG) buffer;
- dp->dp_Arg3 = bufSize;
- SendPkt(dp, (struct MsgPort *) ((struct FileHandle *) BADDR(cis))->fh_Type, port);
- }
-
- if (rsigs & DeviceIOSignal(MySerReq))
- { LONG error;
- LONG result;
-
- if ((error = DeviceIOWait(MySerReq)))
- { SerialShowError(error);
- #ifdef USE_ABORTPKT
- AbortPkt(port, dp);
- WaitPort(port);
- #endif
- status = 10;
- goto ExitSerialTerminal;
- }
- putchar(*SerBuffer);
- fflush(stdout);
-
- do
- { DeviceIODo(MySerReq, SDCMD_QUERY);
- if ((result = SerReq->IOSer.io_Actual))
- { SerReq->IOSer.io_Data = SerBuffer;
- SerReq->IOSer.io_Length = MIN(sizeof(SerBuffer)-1, SerReq->IOSer.io_Actual);
- if ((error = DeviceIODo(MySerReq, CMD_READ)))
- { SerialShowError(error);
- }
- fwrite(SerBuffer, SerReq->IOSer.io_Actual, 1, stdout);
- fflush(stdout);
- }
- }
- while (result);
-
- SerReq->IOSer.io_Length = 1;
- SerReq->IOSer.io_Data = SerBuffer;
- DeviceIOSend(MySerReq, CMD_READ);
- }
- }
-
-
- ExitSerialTerminal:
- if (SerSendReq)
- { DeviceIODelete(SerSendReq);
- }
- if (port)
- { DeleteMsgPort(port);
- }
- if (dp)
- { FreeDosObject(DOS_STDPKT, dp);
- }
- if (!lineMode)
- { SetMode(cis, FALSE);
- }
- if (status >= 0)
- { CleanupAndExit(status);
- }
- if (VerboseMode)
- { printf(">>> Leaving terminal mode\n");
- }
- }
-
-
-
-
- #ifdef SHOWPARMSCMD
-
- /**
- *** This function shows the current serial parameters.
- **/
- VOID SerialShowParms(VOID)
-
- { STRPTR Parity, Protocol;
- struct IOExtSer *SerReq = (struct IOExtSer *) DeviceIOReq(MySerReq);
-
- printf("\tBaud = %ld\n", SerReq->io_Baud);
- printf("\tDataBits = %ld\n", (ULONG) SerReq->io_ReadLen);
- printf("\tStopBits = %ld\n", (ULONG) SerReq->io_StopBits);
- printf("\tBufSize = %ld\n", SerReq->io_RBufLen);
- if (SerReq->io_SerFlags & SERF_PARTY_ON)
- { if (SerReq->io_SerFlags & SERF_PARTY_ODD)
- { Parity = (STRPTR) "Odd";
- }
- else
- { Parity = (STRPTR) "Even";
- }
- }
- else
- { Parity = (STRPTR) "None";
- }
- printf("\tParity = %s\n", Parity);
- if (SerReq->io_SerFlags & SERF_7WIRE)
- { if (SerReq->io_SerFlags & SERF_XDISABLED)
- { Protocol = (STRPTR) "RTS/CTS";
- }
- else
- { Protocol = (STRPTR) "RTS/CTS, XON/XOFF";
- }
- }
- else
- { if (SerReq->io_SerFlags & SERF_XDISABLED)
- { Protocol = (STRPTR) "None";
- }
- else
- { Protocol = (STRPTR) "XON/XOFF";
- }
- }
- printf("\tProtocol = %s\n\n", Protocol);
- }
-
- #endif /* SHOWPARMSCMD */
-
-
-
-
- /**
- *** Some functions for setting serial parameters.
- **/
- VOID SerialSetBaud(ULONG Baud)
-
- { struct IOExtSer *SerReq = (struct IOExtSer *) DeviceIOReq(MySerReq);
- BYTE error;
-
- if (VerboseMode)
- { printf(">>> Setting serial baud to %ld\n", Baud);
- }
-
- SerReq->io_Baud = Baud;
- if ((error = DeviceIODo(MySerReq, SDCMD_SETPARAMS)))
- { SerialShowError(error);
- }
- }
- VOID SerialSetBufSize(ULONG BufSize)
-
- { struct IOExtSer *SerReq = (struct IOExtSer *) DeviceIOReq(MySerReq);
- BYTE error;
-
- if (VerboseMode)
- { printf(">>> Setting serial buffer size to %ld\n", BufSize);
- }
-
- if (BufSize & 0x3f)
- { fprintf(stderr,
- "Warning: BufSize must be a multiple of 64, rounding up.\n");
- BufSize = (BufSize & 0x3f) + 0x40;
- }
- SerReq->io_RBufLen = BufSize;
- if ((error = DeviceIODo(MySerReq, SDCMD_SETPARAMS)))
- { SerialShowError(error);
- }
- }
-
- #ifdef SETCMD
-
- VOID SerialSetDataBits(UBYTE DataBits)
-
- { struct IOExtSer *SerReq = (struct IOExtSer *) DeviceIOReq(MySerReq);
- BYTE error;
-
- if (VerboseMode)
- { printf(">>> Setting serial data bits to %ld\n", DataBits);
- }
-
- SerReq->io_ReadLen = SerReq->io_WriteLen = DataBits;
- if ((error = DeviceIODo(MySerReq, SDCMD_SETPARAMS)))
- { SerialShowError(error);
- }
- }
- VOID SerialSetStopBits(UBYTE StopBits)
-
- { struct IOExtSer *SerReq = (struct IOExtSer *) DeviceIOReq(MySerReq);
- BYTE error;
-
- if (VerboseMode)
- { printf(">>> Setting serial stop bits to %ld\n", StopBits);
- }
-
- SerReq->io_StopBits = StopBits;
- if ((error = DeviceIODo(MySerReq, SDCMD_SETPARAMS)))
- { SerialShowError(error);
- }
- }
- ULONG SerialSetParity(STRPTR Parity)
-
- { struct IOExtSer *SerReq = (struct IOExtSer *) DeviceIOReq(MySerReq);
- BYTE error;
-
- if (VerboseMode)
- { printf(">>> Setting serial parity to %s\n", Parity);
- }
-
- if (stricmp((char *) Parity, "NONE") == 0)
- { SerReq->io_SerFlags &= ~SERF_PARTY_ON;
- }
- else if (stricmp((char *) Parity, "EVEN") == 0)
- { SerReq->io_SerFlags |= SERF_PARTY_ON;
- SerReq->io_SerFlags &= ~SERF_PARTY_ODD;
- }
- else if (stricmp((char *) Parity, "ODD") == 0)
- { SerReq->io_SerFlags |= (SERF_PARTY_ON|SERF_PARTY_ODD);
- }
- else
- { return(FALSE);
- }
-
- if ((error = DeviceIODo(MySerReq, SDCMD_SETPARAMS)))
- { SerialShowError(error);
- }
- return(TRUE);
- }
- ULONG SerialSetProtocol(STRPTR Protocol)
-
- { struct IOExtSer *SerReq = (struct IOExtSer *) DeviceIOReq(MySerReq);
- BYTE error;
-
- if (!(SerialDecodeProtocol(SerReq, Protocol)))
- { return(FALSE);
- }
-
- if ((error = DeviceIODo(MySerReq, SDCMD_SETPARAMS)))
- { SerialShowError(error);
- }
- return(TRUE);
- }
-
- #endif /* SETCMD */
-
-
-
-
-
-
- /**
- *** This function is used to wait for a certain amount of time.
- ***
- *** This function has nothing to do with serial I/O but it's placed
- *** here so we can use the same timer request as in SerialWait().
- ***
- **/
- LONG TimerWait(LONG secs, LONG millisecs)
-
- { ULONG rsigs;
- struct timerequest *tr = (struct timerequest *) DeviceIOReq(MyTimeReq);
-
- tr->tr_time.tv_secs = secs;
- tr->tr_time.tv_micro = 1000 * millisecs;
- DeviceIOSend(MyTimeReq, TR_ADDREQUEST);
-
- rsigs = Wait( SIGBREAKF_CTRL_C | SIGBREAKF_CTRL_F | DeviceIOSignal(MyTimeReq) );
-
- if (rsigs & SIGBREAKF_CTRL_F)
- { printf("\nCtrl-F\n");
- DeviceIOAbort(MyTimeReq);
- DeviceIOWait(MyTimeReq);
- SerialTerminal(NULL, FALSE, FALSE);
- return(0); /* don't wait any more */
- }
-
- if (rsigs & SIGBREAKF_CTRL_C)
- { printf("\nCtrl-C\n");
- CleanupAndExit(10);
- }
-
- DeviceIOWait(MyTimeReq);
- return(0);
- }
-
-